package sparkCore.net;


import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @Author:lixinlei
 * @Date:2021/6/30 11:17
 **/
public class GenerateNetData {

    public static final String GENDERFILE = "E://gender.csv";
    public static final String NETCLEANFILE = "E://netClean.csv";

    static Random rand  = new Random();
    //初始化学生id列表，在生成性别数据的时候添加数据，在生成上网数据的时候使用数据
    static List<String> stuIdList = new ArrayList<String>();


    /**
     * 生成性别数据
     * Note：
     *     性别数据是有规则的数据，可以不用随机形式
     *     以2年 3个专业 每个专业10个学生为例 共60条数据
     */
    public static void genGenderData(){

        //定义性别数据列表，每生成一条数据添加一条，最后整体写入文件
        List<String> genderList = new ArrayList<String>();

        //通过年份，专业编码和同专业顺序码生成学号
        for (int year = 2018; year <= 2019; year++) {
            for (int major = 101; major <= 103 ; major++) {
                for (int num = 1; num <= 10; num++) {
                    String studentId = year+""+major+String.format("%02d",num);
                    //每个学号对应一个性别，性别随机生成
                    String gender = rand.nextInt(2)+1+"";
                    stuIdList.add(studentId);
                    genderList.add(studentId+","+gender);
                }
            }
        }
        //把性别数据写入文件
        writeFile(GENDERFILE,genderList);
    }

    /**
     * 生成上网数据 共三个字段 学生id，上网时间，下网时间
     * 时间处理中产生的问题：
     *     1.如果直接使用for遍历1000次，加上时间过滤条件最后远远不足1000条数据
     *     2.如果使用while(true) 用count计数，越往后越难满足条件
     *     3.可以在生成数据的时候先判断当前开始时间是否大于原结束时间，
     *       如果大于继续操作，如果不大于，在原结束时间基础上添加秒数
     */
    public static void genNetData(){

        //定义上网数据列表，每生成一条数据添加一条，最后整体写入文件
        List<String> netDataList = new ArrayList<String>();

        //为了避免数据出现交叉
        Map<String,LocalDateTime> currentTimeMap = new HashMap<String,LocalDateTime>();

        //生成1000条上网数据
        for(int i=0;i<1000;i++) {

            //1.从已生成的学生id中随机挑选一个id
            String stuId = stuIdList.get(rand.nextInt(stuIdList.size()));

            //2.随机生成一个开始上网时间
            LocalDateTime startTime_ldt = genRandDateTime(2020);
            //如果当前map中有这个学生的结束时间，并且上次记录的结束时间比这次随机生成的开始时间要晚
            if (currentTimeMap.containsKey(stuId) && currentTimeMap.get(stuId).isAfter(startTime_ldt)) {
                //直接在原有结束时间基础上增加秒数作为新数据的开始时间
                startTime_ldt = currentTimeMap.get(stuId).plusSeconds(rand.nextInt(15*24*3600));
            }

            //设置一个临时变量，通过随机一个0-1之间的数来判断概率
            //95%的概率只在当天内添加，规定添加范围在12小时之内，添加24小时也没有问题(跨一天)
            //5%的概率添加5天的范围
            int temp = 0;
            if (rand.nextDouble()<0.95) {
                temp = 12*3600;
            }else{
                temp = 5*24*3600;
            }

            //随机添加5天内的秒数，作为结束时间
            LocalDateTime endTime_ldt = startTime_ldt.plusSeconds(temp);

            //把结束时间的LocalDateTime类型转成字符串类型
            String startTime = startTime_ldt.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));
            String endTime = endTime_ldt.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));

            //整合各字段，形成最终写入文件的形式
            String netData = stuId+","+startTime+","+endTime;

            //把当前学生最新的结束时间更新到map中
            currentTimeMap.put(stuId,endTime_ldt);
            //添加到数据列表，准备输出数据
            netDataList.add(netData);
        }

        //把数据写入文件
        writeFile(NETCLEANFILE,netDataList);

    }

    /**
     *  根据 年 月 获取对应的月份天数
     */
    public static int getDaysByYearMonth(int year, int month) {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.YEAR, year);
        a.set(Calendar.MONTH, month - 1);
        a.set(Calendar.DATE, 1);
        a.roll(Calendar.DATE, -1);
        int maxDate = a.get(Calendar.DATE);
        return maxDate;
    }

    //获取随机日期时间
    public static LocalDateTime genRandDateTime(int year){
        String month = String.format("%02d",rand.nextInt(12)+1);
        //通过年和月 确定当前月份共有多少天，然后随机日
        String day = String.format("%02d",rand.nextInt(getDaysByYearMonth(year,Integer.parseInt(month)))+1);
        String hour = String.format("%02d",rand.nextInt(24));
        String minute = String.format("%02d",rand.nextInt(60));

        //把随机出来的 年月日时分 变成字符串，转成LocalDataTime类型,方便后面计算
        String randTime = year+"/"+month+"/"+day+" "+hour+":"+minute;
        LocalDateTime randTime_ldt = LocalDateTime.parse(randTime,
                DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm"));
        return randTime_ldt;
    }

    //把数据写入文件
    public static void writeFile(String fileName, Object contexts){
        FileWriter fw = null;
        try {
            fw = new FileWriter(fileName);
            //如果是字符串列表形式，直接遍历写入
            if(contexts instanceof List){
                for (String context : (List<String>)contexts) {
                    fw.write(context+"\n");
                }
            }else if(contexts instanceof Map){
                //如果是键值对形式，把键值对组成字符串写入
                Map<String,String> contextMap = (Map<String,String>)contexts;
                Set<Map.Entry<String, String>> entries = contextMap.entrySet();
                for (Map.Entry<String, String> entry : entries) {
                    fw.write(entry.getKey()+","+entry.getValue()+"\n");
                }
            }
            fw.flush();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        genGenderData();
        genNetData();
    }

}
